﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Diagnostics;
using Components;
using System.Xml;
using UI.UpdateHelper;
using System.Configuration;
using UI.Lib.Factory;

namespace UI.Lib
{
    /// <summary>
    /// 自动更新类
    /// </summary>
    public class AutoUpdaterHelper
    {
        private string upfile = "updatecfg.dat";
        DirectoryInfo info = null;
        FileVersionInfo filevesion = null;
        string webXml = ""; //服务器的版本信息
        public bool hasUpdate = false;
        private string userGuid = "";

        private string nowApp = Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);

        public delegate void ShowHandler();
        //自定义事件，打开下载时窗口时候调用
        public event ShowHandler OnShow;

        private Config config = null;
        private bool bNeedRestart = true;

        public AutoUpdaterHelper()
        {
            CreateCfg();
            config = Config.LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, upfile));
        }

        public AutoUpdaterHelper(string guid)
            : this()
        {
            this.userGuid = guid;
        }

        /// <summary>
        /// 创建本地文件
        /// </summary>
        /// <returns></returns>
        public void CreateCfg()
        {
            string mappPath = string.Concat(Application.StartupPath, "\\", upfile);
            if (File.Exists(mappPath)) return;
            //生成本地描述文件
            {
                StringBuilder str = new StringBuilder();
                info = new DirectoryInfo(Application.StartupPath);
                FileInfo[] files = info.GetFiles();
                foreach (FileInfo file in files)
                {
                    filevesion = FileVersionInfo.GetVersionInfo(file.FullName);
                    str.AppendFormat("<LocalFile name=\"{0}\" lastver=\"{1}\" size=\"{2}\" lastwrtime=\"{3}\" />", file.Name, filevesion.FileVersion, file.Length, file.LastWriteTime.ToString());
                    str.AppendLine();
                }

                string fileTmp = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n<Config xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\r\n<UpdateFileList>\r\n{0}</UpdateFileList>\r\n</Config>";
                CommonUtil.GetInstance.SaveToFileOverride(mappPath, string.Format(fileTmp, str.ToString())); //生成XML文件
            }
        }

        /// <summary>
        /// 更新
        /// </summary>
        public bool Update()
        {
            try
            {
                webXml = CommonHelper.Entity.GetVesionList(); //得到服务器版本信息列表
            }
            catch
            {
                LogHelper.Entity.Out("没有链接上服务器！");
                throw new PsException(1);
            }

            Dictionary<string, RemoteFile> listRemotFile = ParseRemoteXml(webXml); //将服务器返回的字符窜转换成易解析的对象
            if (null == listRemotFile) return true;

            List<DownloadFileInfo> downloadList = new List<DownloadFileInfo>();
            //某些文件不再需要了，删除
            List<LocalFile> preDeleteFile = new List<LocalFile>();
            String updateServer = ConfigurationManager.AppSettings["updateServer"];

            foreach (LocalFile file in config.UpdateFileList)
            {
                if (listRemotFile.ContainsKey(file.Name))
                {
                    RemoteFile rf = listRemotFile[file.Name];
                    //版本或时间二者任一不同，则加入更新列表
                    if (rf.LastVer != file.LastVer || rf.LastUpTime != file.Lastwrtime)
                    {
                        downloadList.Add(new DownloadFileInfo(updateServer + "A?B=" + file.Name, file.Name, rf.LastVer, rf.Size));
                        file.LastVer = rf.LastVer;
                        file.Size = rf.Size;

                        if (rf.NeedRestart)
                            bNeedRestart = true;
                    }

                    listRemotFile.Remove(file.Name);
                }
                else
                {
                    preDeleteFile.Add(file);
                }
            }

            foreach (RemoteFile file in listRemotFile.Values)
            {
                downloadList.Add(new DownloadFileInfo(updateServer + "A?B=" + file.Name, file.Name, file.LastVer, file.Size));
                config.UpdateFileList.Add(new LocalFile(file.Name, file.LastVer, file.Size, file.LastUpTime));

                if (file.NeedRestart)
                    bNeedRestart = true;
            }

            if (downloadList.Count > 0)
            {
                hasUpdate = true;

                DownloadConfirm dc = new DownloadConfirm(downloadList);

                if (this.OnShow != null)
                    this.OnShow();

                if (DialogResult.OK == dc.ShowDialog()) //点击更新按钮
                {
                    foreach (LocalFile file in preDeleteFile)
                    {
                        string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file.Name);
                        if (File.Exists(filePath))
                            File.Delete(filePath);

                        config.UpdateFileList.Remove(file);
                    }

                    return StartDownload(downloadList);
                }

                return false;
            }

            return true;
        }

        private bool StartDownload(List<DownloadFileInfo> downloadList)
        {
            DownloadProgress dp = new DownloadProgress(downloadList);
            if (dp.ShowDialog() == DialogResult.OK)
            {
                //更新成功本地文件
                CommonUtil.GetInstance.SaveToFileOverride(upfile, webXml);

                if (bNeedRestart)
                {
                    MessageBox.Show("程序需要重新启动才能应用更新，请点击确定重新启动程序。", "自动更新", MessageBoxButtons.OK, MessageBoxIcon.Information);

                    //如果更新的文件中存在当前exe文件，则替换为最新的文件
                    if (File.Exists(nowApp + ".tmp"))
                        File.Move(nowApp + ".tmp", nowApp);

                    //如果当前用户已经登录，需要重新注销
                    if (!Context.IsLoginOut)
                    {
                        CommonHelper.Entity.LoginOut(Context.LoginKey);
                    }

                    //然后重启
                    Process.Start(Application.ExecutablePath);
                    Environment.Exit(0);
                }

                return true;
            }

            return false;
        }

        /// <summary>
        /// 将远程文件列表转换格式，方便比较
        /// </summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        private Dictionary<string, RemoteFile> ParseRemoteXml(string xml)
        {
            if (string.IsNullOrEmpty(xml)) return null;

            XmlDocument document = new XmlDocument();
            document.LoadXml(xml);

            Dictionary<string, RemoteFile> list = new Dictionary<string, RemoteFile>();
            XmlNodeList cList = document.DocumentElement.ChildNodes[0].ChildNodes;//UpdateFileList
            foreach (XmlNode node in cList)
            {
                list.Add(node.Attributes["name"].Value, new RemoteFile(node));
            }

            return list;
        }
    }
}
